home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TurboTCP 1.0.1 / Aliases / Terminal pane / CTerminalPane.cp next >
Encoding:
Text File  |  1993-12-10  |  13.7 KB  |  668 lines  |  [TEXT/KAHL]

  1. /*
  2. ** CTerminalPane.cp
  3. **
  4. **    TerminalPane library
  5. **    Terminal display pane
  6. **
  7. **    Copyright © 1993, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTerminalPane.h"
  13.  
  14. #include <Events.h>
  15. #include <Global.h>
  16. #include <LongCoordinates.h>
  17. #include <LongQD.h>
  18. #include <CBureaucrat.h>
  19. #include <CScrollPane.h>
  20.  
  21.  
  22. // global TCL objects
  23.  
  24. extern CBureaucrat *gGopher;
  25.  
  26.  
  27. //    —— contruction/destruction ——
  28.  
  29. /*______________________________________________________________________
  30. **
  31. ** ITerminalPane
  32. **
  33. **    Initialize the pane. Nothing special here. Parameters are all the same as
  34. **    for CPanorama::IPanorama.
  35. **
  36. */
  37.  
  38. void CTerminalPane::ITerminalPane (CView *anEnclosure, CBureaucrat *aSupervisor,
  39.                             short aWidth, short aHeight, short aHEncl, short aVEncl,
  40.                             SizingOption aHSizing, SizingOption aVSizing)
  41.  
  42. {
  43.     LongRect theBounds;
  44.  
  45.     CPanorama::IPanorama(anEnclosure, aSupervisor, aWidth, aHeight, aHEncl, aVEncl,
  46.                         aHSizing, aVSizing);
  47.     
  48.     SetLongRect(&theBounds, 0, 0, sizeX, sizeY);
  49.     SetBounds(&theBounds);
  50.     SetCanBeGopher(TRUE);
  51.     SetWantsClicks(TRUE);
  52.     
  53.     if (member(itsEnclosure, CScrollPane))
  54.         ((CScrollPane *) itsEnclosure)->SetSteps(pixelsX, pixelsY);
  55.     
  56.     blinkCursor = FALSE;
  57.     cursorVis = TRUE;
  58.     lastCursorCol = lastCursorLine = 0;
  59.     lastCursorTick = 0L;
  60.     DoClearScreen();
  61. }
  62.  
  63.  
  64. //    —— drawing  ——
  65.  
  66. /*______________________________________________________________________
  67. **
  68. ** Draw
  69. **
  70. **    Draw characters from the theScreen array onto the real screen.
  71. **
  72. **        area (Rect *):    area to be redrawn (in frame coordinates)
  73. **
  74. */
  75.  
  76. void CTerminalPane::Draw (Rect *area)
  77.  
  78. {
  79.     short    left, top, right, bottom;        // char coordinatates of draw region
  80.     short    dLine;                    // where to draw now
  81.     LongRect    theLongArea;                // frame coordinates of region
  82.     LongPt    theLongPt;
  83.     Point        thePoint;
  84.  
  85.  
  86.     // figure draw region
  87.  
  88.     QDToFrameR(area, &theLongArea);
  89.     left = (theLongArea.left - offsetX) / pixelsX;
  90.     right = (theLongArea.right -offsetX + 1) / pixelsX;
  91.     top = (theLongArea.top - offsetY) / pixelsY;
  92.     bottom = (theLongArea.bottom -offsetY + 1) / pixelsY;
  93.  
  94.  
  95.     // do range checking
  96.  
  97.     left = Max(left, 0);
  98.     top = Max(top, 0);
  99.     right = Min(right, maxX-1);
  100.     bottom = Min(bottom, maxY-1);
  101.  
  102.  
  103.     // hard-wire for Monaco 9: Mom, don’t look at this code!
  104.  
  105.     TextFont(4);
  106.     TextFace(0);
  107.     TextSize(9);
  108.  
  109.  
  110.     // draw the stuff
  111.  
  112.     if (left <= right) {
  113.         HLock((Handle) this);
  114.         dLine = top;
  115.         while (dLine <= bottom) {
  116.             SetLongPt(&theLongPt, left * pixelsX, dLine * pixelsY);
  117.             FrameToQD(&theLongPt, &thePoint);
  118.             MoveTo(thePoint.h + offsetX, thePoint.v + offsetY + pixelsY-2);
  119.             DrawText(&theScreen[dLine][left], 0, right-left+1);
  120.             dLine++;
  121.         }
  122.         HUnlock((Handle) this);
  123.     }
  124.  
  125.  
  126.     // check to see if we overwrote the cursor
  127.  
  128.     if ((left <= theColumn) && (right >= theColumn) &&
  129.      (top <= theLine) && (bottom >= theLine) && cursorVis)
  130.          InvertCursor(theColumn, theLine);
  131.     
  132. }
  133.  
  134.  
  135. //    —— blinking cursor support ——
  136.  
  137. /*______________________________________________________________________
  138. **
  139. ** Dawdle
  140. **
  141. **    Blink the cursor if necessary. Cursor blinks at the user-defined rate for insertion point
  142. **    blinking.
  143. **
  144. **        maxSleep (long *):    maximum sleep value, updated if necessary
  145. **
  146. */
  147.  
  148. void CTerminalPane::Dawdle (long *maxSleep)
  149.  
  150. {
  151.     CPanorama::Dawdle(maxSleep);
  152.     if (blinkCursor) {
  153.         *maxSleep = Min(*maxSleep, GetCaretTime());
  154.         if (Ticks >= lastCursorTick + GetCaretTime()) {
  155.             cursorVis = !cursorVis;
  156.             lastCursorTick = Ticks;
  157.             InvalCharRect(theColumn, theLine, theColumn, theLine);
  158.         }
  159.     }
  160. }
  161.  
  162.  
  163. /*______________________________________________________________________
  164. **
  165. ** BecomeGopher
  166. **
  167. **    Become the gopher (or leave gopher status). All our routine does is force a refresh
  168. **    of the cursor.
  169. **
  170. **        fBecoming (Boolean):        TRUE if becoming gopher
  171. **
  172. **        return (Boolean):        TRUE if successful in changing status
  173. **
  174. */
  175.  
  176. Boolean CTerminalPane::BecomeGopher (Boolean fBecoming)
  177.  
  178. {
  179.     if (!fBecoming)
  180.         cursorVis = TRUE;
  181.     InvalCharRect(theColumn, theLine, theColumn, theLine);
  182.     return CPanorama::BecomeGopher(fBecoming);
  183. }
  184.  
  185.  
  186. /*______________________________________________________________________
  187. **
  188. ** SetBlinking
  189. **
  190. **    Turns on or off cursor blinking.
  191. **
  192. **        blinkMode (Boolean):        TRUE to enable cursor blinking
  193. **
  194. */
  195.  
  196. void CTerminalPane::SetBlinking (Boolean blinkMode)
  197.  
  198. {
  199.     blinkCursor = blinkMode;
  200.     if ((blinkMode)    && (gGopher == this)) {
  201.         lastCursorCol = theColumn;
  202.         lastCursorLine = theLine;
  203.         CursorMoved();
  204.     }
  205.     else {
  206.         cursorVis = TRUE;
  207.         InvalCharRect(theColumn, theLine, theColumn, theLine);
  208.     }
  209. }
  210.  
  211.  
  212. //    —— scrolling ——
  213.  
  214. /*______________________________________________________________________
  215. **
  216. ** ScrollToSelection
  217. **
  218. **    Ensure that the current cursor location is visible.
  219. **
  220. */
  221.  
  222. void CTerminalPane::ScrollToSelection (void)
  223.  
  224. {
  225.     LongRect    theVisRect;
  226.     LongRect    theCharRect;
  227.     LongRect    tempRect;
  228.     LongPt    whereTo;
  229.     Boolean    needsScroll = FALSE;
  230.  
  231.  
  232.     // figure out panorama coordinates of what’s visible...
  233.     //    this SHOULD be easier (hint, hint, Symantec)
  234.     
  235.     GetPosition(&whereTo);
  236.     GetBounds(&tempRect);
  237.     if (!(PtInLongRect(&whereTo, &tempRect))) {
  238.         whereTo.h = 0;                        // scroll position is just plain bonkers
  239.         whereTo.v = 0;
  240.         needsScroll = TRUE;
  241.     }
  242.     
  243.     GetAperture(&tempRect);
  244.     theVisRect.left = whereTo.h;
  245.     theVisRect.top = whereTo.v;
  246.     theVisRect.right = whereTo.h + (tempRect.right - tempRect.left);
  247.     theVisRect.bottom = whereTo.v + (tempRect.bottom - tempRect.top);
  248.  
  249.  
  250.     // figure out where our cursor is
  251.  
  252.     CalcCharRect(theColumn, theLine, theColumn, theLine, &theCharRect);
  253.     theCharRect.left -= offsetX;
  254.     theCharRect.top -= offsetY;
  255.     theCharRect.right += offsetX;
  256.     theCharRect.bottom += offsetY;
  257.  
  258.  
  259.     // scroll if necessary
  260.  
  261.     if (theCharRect.bottom > theVisRect.bottom) {
  262.         whereTo.v = Max(theCharRect.bottom, theVisRect.bottom) -
  263.                         (theVisRect.bottom - theVisRect.top);
  264.         needsScroll = TRUE;
  265.     }
  266.     if (theCharRect.top < theVisRect.top) {
  267.         whereTo.v = Min(Min(theCharRect.top, theVisRect.top), 0);
  268.         needsScroll = TRUE;
  269.     }
  270.  
  271.     if (theCharRect.right > theVisRect.right) {
  272.         whereTo.h = Max(theCharRect.right, theVisRect.right) -
  273.                         (theVisRect.right - theVisRect.left);
  274.         needsScroll = TRUE;
  275.     }
  276.     if (theCharRect.left < theVisRect.left) {
  277.         whereTo.h = Min(Min(theCharRect.left, theVisRect.left), 0);
  278.         needsScroll = TRUE;
  279.     }
  280.  
  281.     if (needsScroll) {
  282.         ScrollTo(&whereTo, FALSE);
  283.         Refresh();
  284.     }
  285. }
  286.  
  287.  
  288. //    —— terminal emulation methods ——
  289.  
  290. /*______________________________________________________________________
  291. **
  292. ** DoClearScreen
  293. **
  294. **    Clear the screen and move the cursor to (0,0).
  295. **
  296. */
  297.  
  298. void CTerminalPane::DoClearScreen (void)
  299.  
  300. {
  301.     register short x, y;
  302.     
  303.     theLine = theColumn = 0;
  304.     CursorMoved();
  305.  
  306.     for (y = 0; y < maxY; ++y)
  307.         for (x = 0; x < maxX; ++x)
  308.             theScreen[y][x] = ' ';
  309.     Refresh();
  310. }
  311.  
  312.  
  313. /*______________________________________________________________________
  314. **
  315. ** DoWriteChar
  316. **
  317. **    Write a character to the terminal. This method handles *basic* terminal emulation.
  318. **    To provide more sophisticated emulation, override this method.
  319. **
  320. **        theChar (char):        the character to write
  321. **
  322. */
  323.  
  324. void CTerminalPane::DoWriteChar (char theChar)
  325.  
  326. {
  327.  
  328.     // parse a few control characters
  329.  
  330.     switch (theChar) {
  331.  
  332.         case charNUL:
  333.             break;
  334.  
  335.         case charBEL:
  336.             SysBeep(0);
  337.             break;
  338.  
  339.         case charBS:
  340.             if (theColumn > 0)
  341.                 theColumn--;
  342.             CursorMoved();
  343.             break;
  344.  
  345.         case charHT:
  346.             theColumn = ((short) ((theColumn + 7) / 8)) * 8;
  347.             if (theColumn >= maxX)
  348.                 theColumn = maxX-1;
  349.             CursorMoved();
  350.             break;
  351.             
  352.         case charLF:
  353.             if (theLine < maxY-1)
  354.                 theLine++;
  355.             else
  356.                 ScrollTerm();
  357.             CursorMoved();
  358.             ScrollToSelection();
  359.             break;
  360.             
  361.         case charFF:
  362.             DoClearScreen();
  363.             ScrollToSelection();
  364.             break;
  365.             
  366.         case charCR:
  367.             theColumn = 0;
  368.             CursorMoved();
  369.             break;
  370.         
  371.         default:
  372.             theScreen[theLine][theColumn] = theChar;
  373.             InvalCharRect(theColumn, theLine, theColumn, theLine);
  374.             if (theColumn < maxX)
  375.                 theColumn++;
  376.             CursorMoved();
  377.     }
  378. }
  379.  
  380.  
  381. /*______________________________________________________________________
  382. **
  383. ** DoWriteStr
  384. **
  385. **    Write a string to the terminal. This method is optimized to handle text strings. It skips
  386. **    any control characters and sends them directly to DoWriteChar.
  387. **
  388. **        theStr (char *):    the string to write (C string)
  389. **
  390. */
  391.  
  392. void CTerminalPane::DoWriteStr (char *theStr)
  393.  
  394. {
  395.     short leftCol;
  396.  
  397.  
  398.     // optimize for text characters
  399.     
  400.     while (*theStr) {
  401.         if (*theStr >= ' ') {
  402.             leftCol = theColumn;
  403.             while (*theStr >= ' ') {
  404.                 theScreen[theLine][theColumn] = *(theStr++);
  405.                 if (theColumn < maxX)
  406.                     theColumn++;
  407.             }
  408.             InvalCharRect(leftCol, theLine, theColumn, theLine);
  409.             CursorMoved();
  410.         }
  411.         if (*theStr)
  412.             DoWriteChar(*(theStr++));
  413.     }
  414. }
  415.  
  416.  
  417. /*______________________________________________________________________
  418. **
  419. ** DoWriteBfr
  420. **
  421. **    Write the contents of a text buffer to the terminal. This method
  422. **    merely dishes out the characters to the DoWriteChar method.
  423. **
  424. **        theStr (char *):    the buffer to write
  425. **        theSize (short):    size of the data buffer
  426. **
  427. */
  428.  
  429. void CTerminalPane::DoWriteBfr (char *theStr, short theSize)
  430.  
  431. {
  432.     while (theSize--)
  433.         DoWriteChar(*(theStr++));
  434. }
  435.  
  436.  
  437. /*______________________________________________________________________
  438. **
  439. ** DoWriteCharNum
  440. **
  441. **    Write a character number to the terminal. Provided as a debugging routine
  442. **    by other classes. The number is bracketed by the two characters indicated, i.e.
  443. **    if you call ::DoWriteCharNum('!', '[', ']'), you get [33] written to the terminal.
  444. **
  445. **        theChar (char):        the character number to write
  446. **        leftBracket (char):    prefix to character number
  447. **        rightBracket (char):    suffix to character number
  448. **
  449. */
  450.  
  451. void CTerminalPane::DoWriteCharNum (char theChar, char leftBracket, char rightBracket)
  452.  
  453. {
  454.     Str255 cNumber;
  455.  
  456.     if (leftBracket)
  457.         DoWriteChar(leftBracket);
  458.  
  459.     NumToString((short) theChar, cNumber);
  460.     cNumber[cNumber[0]+1] = '\0';
  461.     DoWriteStr((char *) (&cNumber)+1);
  462.  
  463.     if (rightBracket)    
  464.         DoWriteChar(rightBracket);
  465. }
  466.  
  467.  
  468. /*______________________________________________________________________
  469. **
  470. ** DoEraseChar
  471. **
  472. **    Erase one character from screen (backspace).
  473. **
  474. */
  475.  
  476. void CTerminalPane::DoEraseChar (void)
  477.  
  478. {
  479.     register short x;
  480.     
  481.     if (theColumn > 0) {
  482.         theColumn--;
  483.         for (x = theColumn; x < maxX-1; x++)
  484.             theScreen[theLine][x] = theScreen[theLine][x+1];
  485.         theScreen[theLine][maxX-1] = ' ';
  486.         InvalCharRect(theColumn, theLine, maxX-1, theLine);
  487.         CursorMoved();
  488.     }
  489. }
  490.  
  491.  
  492. /*______________________________________________________________________
  493. **
  494. ** DoEraseLine
  495. **
  496. **    Move the cursor back to beginning of line & erase line.
  497. **
  498. */
  499.  
  500. void CTerminalPane::DoEraseLine (void)
  501.  
  502. {
  503.     theColumn = 0;
  504.     ClearToEOL(0, theLine);
  505.     CursorMoved();
  506. }
  507.  
  508.  
  509. //    —— private screen handling methods ——
  510.  
  511. /*______________________________________________________________________
  512. **
  513. ** ClearToEOL (protected method)
  514. **
  515. **    Clear from the indicated point to the end of a line. Upper left
  516. **    corner is (0,0).
  517. **
  518. **        col (short):    first column in line to clear
  519. **        line (short):    line to be cleared
  520. **
  521. */
  522.  
  523. void CTerminalPane::ClearToEOL (short col, short line)
  524.  
  525. {
  526.     InvalCharRect(col, line, maxX-1, line);
  527.     while (col < maxX)
  528.         theScreen[line][col++] = ' ';
  529. }
  530.  
  531.  
  532. /*______________________________________________________________________
  533. **
  534. ** ClearToEOS (protected method)
  535. **
  536. **    Clear from the indicated point to the end of the screen. Upper left
  537. **    corner is (0,0).
  538. **
  539. **        col (short):    first column in first line to clear
  540. **        line (short):    first line to be cleared
  541. **
  542. */
  543.  
  544. void CTerminalPane::ClearToEOS (short col, short line)
  545.  
  546. {
  547.     while (line < maxY) {
  548.         ClearToEOL(col, line++);
  549.         col = 0;
  550.     }
  551. }
  552.  
  553.  
  554. /*______________________________________________________________________
  555. **
  556. ** ScrollTerm
  557. **
  558. **    Push everything on screen up one line.
  559. **
  560. */
  561.  
  562. void CTerminalPane::ScrollTerm (void)
  563.  
  564. {
  565.     BlockMove(&theScreen[1][0], &theScreen[0][0], (maxY-1) * maxX);
  566.     ClearToEOL(0, maxY-1);
  567.     Refresh();
  568. }
  569.  
  570.  
  571. /*______________________________________________________________________
  572. **
  573. ** InvalCharRect (protected method)
  574. **
  575. **    Invalidate a section of the pane based on the character coordinates
  576. **    provided. Upper left corner is (0,0).
  577. **
  578. **        left (short):        left edge of character rectangle
  579. **        top (short):        top edge
  580. **        right (short):        right edge, inclusive
  581. **        bottom (short):        bottom edge, inclusive
  582. **
  583. */
  584.  
  585. void CTerminalPane::InvalCharRect (short left, short top, short right, short bottom)
  586.  
  587. {
  588.     LongRect    theLongRect;
  589.     
  590.     CalcCharRect(left, top, right, bottom, &theLongRect);
  591.     Prepare();
  592.     RefreshLongRect(&theLongRect);
  593. }
  594.  
  595.  
  596. /*______________________________________________________________________
  597. **
  598. ** CursorMoved
  599. **
  600. **    Update the blinking cursor block.
  601. **
  602. */
  603.  
  604. void CTerminalPane::CursorMoved (void)
  605.  
  606. {
  607.     cursorVis = TRUE;
  608.     lastCursorTick = Ticks;
  609.     InvalCharRect(lastCursorCol, lastCursorLine, lastCursorCol, lastCursorLine);
  610.     InvalCharRect(theColumn, theLine, theColumn, theLine);
  611.     lastCursorCol = theColumn;
  612.     lastCursorLine = theLine;
  613. }
  614.  
  615.  
  616. /*______________________________________________________________________
  617. **
  618. ** CalcCharRect (protected method)
  619. **
  620. **    Calculate the screen coordinates for a specified rectangle of
  621. **    character coordinates. Upper left corner is (0,0).
  622. **
  623. **        left (short):            left edge of char rectangle
  624. **        top (short):            top edge
  625. **        right (short):            right edge, inclusize
  626. **        bottom (short):            bottom edge, inclusive
  627. **        theRect (LongRect *):    coordinates returned to this rectangle
  628. **
  629. */
  630.  
  631. void CTerminalPane::CalcCharRect (short left, short top, short right, short bottom,
  632.                             LongRect *theRect)
  633.  
  634. {
  635.     SetLongRect(theRect,
  636.                 (long) left * pixelsX + offsetX,
  637.                 (long) top * pixelsY + offsetY,
  638.                 (long) (right+1) * pixelsX + offsetX,
  639.                 (long) (bottom+1) * pixelsY + offsetY);
  640. }
  641.  
  642.  
  643. /*______________________________________________________________________
  644. **
  645. ** InvertCursor
  646. **
  647. **    Invert a single character.
  648. **
  649. **        col (short):    the column number
  650. **        line (short):    the line number
  651. **
  652. */
  653.  
  654. void CTerminalPane::InvertCursor (short col, short line)
  655.  
  656. {
  657.     LongRect    theLongRect;
  658.     Rect        theRect;
  659.     
  660.     CalcCharRect(col, line, col, line, &theLongRect);
  661.     LongToQDRect(&theLongRect, &theRect);
  662.     InvertRect(&theRect);
  663.     if (gGopher != this) {
  664.         InsetRect(&theRect, 1, 1);
  665.         InvertRect(&theRect);
  666.     }
  667. }
  668.